#include "timer.h"

namespace zsylar
{

/**
 * @brief 从时间堆中删除当前定时器
 * @return 如果成功删除返回 true，否则返回 false
 */
bool Timer::cancel()
{
    // 获取写锁，确保线程安全
    std::unique_lock<std::shared_mutex> write_lock(m_manager->m_mutex);

    // 如果回调函数为空，表示定时器已经被取消，直接返回 false
    if (m_cb == nullptr)
    {
        return false;
    }
    else
    {
        // 将回调函数置为空，表示取消定时器
        m_cb = nullptr;
    }

    // 从定时器管理器中查找当前定时器
    // shared_from_this()
    // 这个函数是一个模板函数，主要用于查找某种容器中的元素，并返回一个迭代器指向找到的元素
    auto it = m_manager->m_timers.find(shared_from_this());
    if (it != m_manager->m_timers.end())
    {
        // 如果找到，则从定时器集合中删除
        m_manager->m_timers.erase(it);  
    }

    // 返回 true 表示成功取消定时器
    return true;
}

/**
 * @brief 刷新当前定时器的状态，更新其在时间堆中的位置
 * @return 如果成功刷新返回 true，否则返回 false
 */
bool Timer::refresh()
{
    // 获取写锁，确保线程安全
    std::unique_lock<std::shared_mutex> write_lock(m_manager->m_mutex);

    // 如果回调函数为空，表示定时器已经被取消，直接返回 false
    if (!m_cb)
    {
        return false;
    }

    // 查找当前定时器在管理器中的位置
    auto it = m_manager->m_timers.find(shared_from_this());
    if (it == m_manager->m_timers.end())
    {
        return false; // 如果未找到，返回 false
    }

    // 从定时器集合中删除当前定时器
    m_manager->m_timers.erase(it);
    
    // 更新绝对超时时间为当前时间加上相对超时时间
    m_next = std::chrono::system_clock::now() + std::chrono::milliseconds(m_ms);
    
    // 重新插入到定时器集合中
    m_manager->m_timers.insert(shared_from_this());
    
    return true; // 返回 true 表示刷新成功 
}

/**
 * @brief 重设定时器的超时时间
 * @param ms 新的超时时间，单位为毫秒
 * @param from_now 是否从当前时间开始计算新的超时时间
 * @return 如果成功重设返回 true，否则返回 false
 */
bool Timer::reset(uint64_t ms, bool from_now)
{
    // 如果新的超时时间和当前的相同，并且不是从现在开始，则直接返回 true
    if (ms == m_ms && !from_now)
    {
        return true;
    }

    {
        // 获取写锁，确保线程安全
        std::unique_lock<std::shared_mutex> write_lock(m_manager->m_mutex);

        // 如果回调函数为空，表示定时器已经被取消，直接返回 false
        if (!m_cb)
        {
            return false;
        }

        // 查找当前定时器在管理器中的位置
        auto it = m_manager->m_timers.find(shared_from_this());
        if (it == m_manager->m_timers.end())
        {
            return false; // 如果未找到，返回 false
        }

        // 从定时器集合中删除当前定时器
        m_manager->m_timers.erase(it);
    }

    // 重新设置超时时间
    auto start = from_now ? std::chrono::system_clock::now() : m_next - std::chrono::milliseconds(m_ms);
    
    m_ms = ms; // 更新相对超时时间
    m_next = start + std::chrono::milliseconds(m_ms); // 更新绝对超时时间
    
    // 重新插入到定时器集合中
    m_manager->addTimer(shared_from_this()); 
    return true; // 返回 true 表示重设成功
}

// 构造函数
Timer::Timer(uint64_t ms, std::function<void()> cb, bool recurring, TimerManager* manager)
    : m_recurring(recurring), m_ms(ms), m_cb(cb), m_manager(manager)
{
    // 初始化绝对超时时间为当前时间加上相对超时时间
    auto now = std::chrono::system_clock::now();
    m_next = now + std::chrono::milliseconds(m_ms);
}

// 比较函数，用于在时间堆中排序定时器
bool Timer::Comparator::operator()
    (const std::shared_ptr<Timer>& lhs, const std::shared_ptr<Timer>& rhs) const
{
    // 确保两个定时器都不为空
    assert(lhs != nullptr && rhs != nullptr);
    // 比较两个定时器的绝对超时时间
    return lhs->m_next < rhs->m_next;
}

///////////////////////////////////////////////////////////////////////////////
TimerManager::TimerManager()
{
    // 初始化上次检查系统时间是否回退的绝对时间为当前时间
    m_previousTime = std::chrono::system_clock::now();
}

TimerManager::~TimerManager()
{
}

// 添加一个定时器
std::shared_ptr<Timer> TimerManager::addTimer(uint64_t ms, 
                                              std::function<void()> cb, 
                                              bool recurring)
{
    // 创建一个新的定时器对象
    std::shared_ptr<Timer> timer(new Timer(ms, cb, recurring, this));
    // 将定时器添加到管理器中
    addTimer(timer);
    return timer; // 返回新创建的定时器
}

// 如果条件存在，执行cb()
static void OnTimer(std::weak_ptr<void> weak_cond, std::function<void()> cb)
{
    // 尝试获取条件的强引用
    std::shared_ptr<void> tmp = weak_cond.lock();
    if (tmp)
    {
        // 如果条件存在，执行回调函数
        cb();
    }
}

// 添加一个带条件的定时器
std::shared_ptr<Timer> TimerManager::addConditionTimer(uint64_t ms,
                                                       std::function<void()> cb,
                                                       std::weak_ptr<void> weak_cond,
                                                       bool recurring)
{
    // 使用 std::bind 绑定条件和回调函数
    return addTimer(ms, std::bind(&OnTimer, weak_cond, cb), recurring);
}   

// 拿到堆中最近的超时时间
uint64_t TimerManager::getNextTimer()
{
    std::shared_lock<std::shared_mutex> read_lock(m_mutex);

    m_tickled = false; // 重置 tickled 标志位
    if (m_timers.empty())
    {
        // 如果定时器堆为空，返回最大值：表示无效或特殊值
        return ~0ull;   
    }

    // 获取当前时间
    auto now = std::chrono::system_clock::now();
    // 获取下一个定时器的绝对超时时间
    auto time = (*m_timers.begin())->m_next;
    if (now >= time)
    {
        // 如果当前时间已经超过下一个定时器的超时时间，返回 0：表示立即触发
        return 0;
    }
    else
    {
        // 计算下一个定时器的剩余时间，并转换为毫秒
        auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(time - now);
        return static_cast<uint64_t>(duration.count());
    }
}

// 去除所有超时定时器的回调函数
// 该函数会从定时器堆中找到所有已经超时的定时器，并将它们的回调函数存储到传入的 cbs 容器中
// 用于批量处理超时事件，避免逐个检查定时器是否超时。
void TimerManager::listExpiredCb(std::vector<std::function<void()>>& cbs)
{
    // 获取当前时间
    auto now = std::chrono::system_clock::now();
    std::unique_lock<std::shared_mutex> write_lock(m_mutex); // 获取写锁
    bool rollover = detectClockRollover(); // 检测系统时间是否回退

    while (!m_timers.empty() && rollover || !m_timers.empty() && (*m_timers.begin())->m_next <= now)
    {
        // 获取最早的定时器
        std::shared_ptr<Timer> temp = *m_timers.begin();
        m_timers.erase(m_timers.begin()); // 从堆中删除该定时器

        // 将定时器的回调函数添加到 cbs 容器中
        cbs.push_back(temp->m_cb);
        if (temp->m_recurring)
        {
            // 如果是循环定时器，则重新设置其超时时间
            temp->m_next = now + std::chrono::milliseconds(temp->m_ms);
            m_timers.insert(temp); // 重新插入到堆中
        }
        else
        {
            // 如果不是循环定时器，则将回调函数置为空，表示已取消
            temp->m_cb = nullptr;
        }
    }
}

// 函数用于检查定时器堆中是否存在任何定时器
bool TimerManager::hasTimer()
{
    std::shared_lock<std::shared_mutex> read_lock(m_mutex);
    return !m_timers.empty(); // 检查定时器堆是否为空
}

// 添加定时器到堆中
void TimerManager::addTimer(std::shared_ptr<Timer> timer)
{
    bool at_front = false; // 标志位，表示是否是最早的定时器

    {
        std::unique_lock<std::shared_mutex> write_lock(m_mutex); // 获取写锁
        auto it = m_timers.insert(timer).first; // 插入定时器到堆中
        at_front = (it == m_timers.begin()) && !m_tickled; // 检查是否是最早的定时器且未被触发
        if (at_front)
        {
            m_tickled = true; // 设置 tickled 标志位，表示有新的定时器被添加到堆中
        }
    }

    if (at_front)
    {
        // 如果是最早的定时器，触发 onTimerInsertedAtFront() 回调
        onTimerInsertedAtFront();
    }
}

bool TimerManager::detectClockRollover()
{
    bool rollover = false; // 标志位，表示是否发生了时间回退
    auto now = std::chrono::system_clock::now(); // 获取当前时间    
    if (now < (m_previousTime - std::chrono::milliseconds(60 * 60 * 1000)))
    {
        // 如果当前时间小于上次记录的时间，表示发生了时间回退
        rollover = true;
    }
    return rollover; // 返回是否发生了时间回退
}

}